package com.pronosticnews.server.services;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pronosticnews.client.services.UserService;
import com.pronosticnews.server.domain.dao.UserDao;
import com.pronosticnews.server.domain.model.Role;
import com.pronosticnews.server.domain.model.User;
import com.pronosticnews.shared.model.UserDto;

import fr.ysa.persistence.IDao;
import fr.ysa.services.ImplService;
import fr.ysa.services.ServiceException;

@Service("userService")
@Transactional
public class UserServiceImpl extends ImplService<User, UserDto> implements
		UserService, UserDetailsService {

	@Autowired
	UserDao userDao;

	@Override
	public IDao<User> getDao() {
		return userDao;
	}

	@Override
	public Class<User> getEntityClass() {
		return User.class;
	}

	@Override
	public Class<UserDto> getEntityDtoClass() {
		return UserDto.class;
	}
	
	@Override
	public UserDto sauvegarder(UserDto user) throws ServiceException {
		try {
			String mdpEncode = encode(user.getPassword(),"SHA-1");
			user.setPassword(mdpEncode);
			UserDto userSaved = super.sauvegarder(user);
			return userSaved;
		} catch (NoSuchAlgorithmException e) {
			throw new ServiceException(e.getMessage());
		}
	}

	@Override
	public UserDto modifier(UserDto user) throws ServiceException {
		try {
			String mdpEncode = encode(user.getPassword(),"SHA-1");
			user.setPassword(mdpEncode);
			return super.modifier(user);
		} catch (NoSuchAlgorithmException e) {
			throw new ServiceException(e.getMessage());
		}
	}

	@Override
	public UserDetails loadUserByUsername(String login)
			throws UsernameNotFoundException {
		login = login.toLowerCase();
		final User user = userDao.trouverByLogin(login);
		
		if (user == null) {
			throw new UsernameNotFoundException("Utilisateur '" + login + "' inconnu");
		}
		
		return new UserDetails() {

			private static final long serialVersionUID = 8403969688307061114L;

			@Override
			public boolean isEnabled() {
				return true;
			}

			@Override
			public boolean isCredentialsNonExpired() {
				return true;
			}

			@Override
			public boolean isAccountNonLocked() {
				return true;
			}

			@Override
			public boolean isAccountNonExpired() {
				return true;
			}

			@Override
			public String getUsername() {
				return user.getLogin();
			}

			@Override
			public String getPassword() {
				return user.getPassword();
			}

			@Override
			public Collection<? extends GrantedAuthority> getAuthorities() {
				Set<Role> roles = user.getRoles();
				List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
				for (Role role : roles) {
					auths.add(new SimpleGrantedAuthority(role.getRole()));
				}
				return auths;
			}
		};
	}

	private String encode(String password, String algorithm)
			throws NoSuchAlgorithmException {
		byte[] hash = null;
		try {
			MessageDigest md = MessageDigest.getInstance(algorithm);
			hash = md.digest(password.getBytes());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < hash.length; ++i) {
			String hex = Integer.toHexString(hash[i]);
			if (hex.length() == 1) {
				sb.append(0);
				sb.append(hex.charAt(hex.length() - 1));
			} else {
				sb.append(hex.substring(hex.length() - 2));
			}
		}
		return sb.toString();
	}

	@Override
	public UserDto getConnected() {
		SecurityContext context = SecurityContextHolder.getContext();
		Authentication auth = context.getAuthentication();
		UserDto userConnected = new UserDto();
		userConnected.setLogin(auth.getName());
		return userConnected;
	}	
	
}
